using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using TXLooker.Common.Core;
using TXLooker.Common.UI;
using TXLooker.WorkItemExtention.Core;

namespace TXLooker.WorkItemExtention.UI
{

    /// <summary>
    /// This control is tree map of the TFS list
    /// </summary>
    internal partial class TFSTreeCtrl : UserControl
    {
        private Guid m_guidNodeExpand;
        // Methods
        public TFSTreeCtrl()
        {
            InitializeComponent();

            AutoScaleDimensions = new SizeF(6f, 13f);
            AutoScaleMode = AutoScaleMode.Font;

            m_tvTFSMap.AfterSelect += OnAfterNodeSelect;
            m_tvTFSMap.KeyUp += OnTfsTreeKeyUp;
        }

        private void EnsureNodeIsVisible(TreeNode node)
        {
            node.TreeView.SelectedNode = node;
            do
            {
                node = node.Parent;
                node.Expand();
            }
            while (node.Parent != null);
        }

        private void ExpandSelectedNode()
        {
            TreeNode node = null;
            if (this.GuidNodeExpand != Guid.Empty)
            {
                node = this.m_itemsTreeMAP[this.GuidNodeExpand];
            }
            if (node != null)
            {
                this.EnsureNodeIsVisible(node);
                this.SelectedObject = WIObject.GetObject(this.GuidNodeExpand);
            }
        }

        private static void InitImage<T>(T item, TreeNode node) where T : WIObject
        {
            switch (item.Type)
            {
                case WIObjectType.Server:
                    node.ImageIndex = 0;
                    break;

                case WIObjectType.Project:
                    node.ImageIndex = 1;
                    break;

                case WIObjectType.QueriesRoot:
                    node.ImageIndex = 2;
                    break;

                case WIObjectType.QueriesGroup:
                    if ((item as WIQueriesGroup).QueryScope != QueryScope.Public)
                    {
                        node.ImageIndex = 4;
                        break;
                    }
                    node.ImageIndex = 3;
                    break;

                case WIObjectType.Query:
                    node.ImageIndex = 5;
                    break;
            }
        }

        private void InitItems<T>(IEnumerable<T> items) where T : WIObject
        {
            this.m_tvTFSMap.BeginUpdate();
            List<T> list = new List<T>(items);
            try
            {
                if (list.Count != 0)
                {
                    lock (this.m_itemsTreeMAP)
                    {
                        T local = list[0];
                        TreeNode parent = this.m_itemsTreeMAP[local.ID].Parent;
                        TreeNodeCollection nodes = (parent == null) ? this.m_tvTFSMap.Nodes : parent.Nodes;
                        foreach (TreeNode node2 in this.InitNodes<T>(items))
                        {
                            nodes.Add(node2);
                        }
                    }
                }
            }
            finally
            {
                this.m_tvTFSMap.EndUpdate();
            }
        }

        private IEnumerable<TreeNode> InitNodes<T>(IEnumerable<T> items) where T : WIObject
        {
            List<TreeNode> list = new List<TreeNode>();
            lock (this.m_itemsTreeMAP)
            {
                foreach (T local in items)
                {
                    local.NewChildItems += new TFEventHandler<IEnumerable<WIObject>>(this.OnNewChildItems<WIObject>);
                    local.PreRemoveChildItems += new TFEventHandler<IEnumerable<WIObject>>(this.OnPreRemoveChildItems<WIObject>);
                    TreeNode node = new TreeNode(local.FolderName);
                    InitImage<T>(local, node);
                    node.Tag = new TreeNodeTag<WIObjectType>(local.Type, local);
                    if (!m_itemsTreeMAP.ContainsKey(local.ID))
                    {
                        m_itemsTreeMAP.Add(local.ID, node);
                    }


                    foreach (TreeNode node2 in this.InitNodes<WIObject>(local.ChildItems))
                    {
                        node.Nodes.Add(node2);
                    }
                    list.Add(node);
                }
            }
            return list;
        }

        public void LoadF()
        {
            MethodInvoker method = delegate
            {
                this.LoadTree();
            };
            if (base.InvokeRequired)
            {
                base.Invoke(method);
            }
            else
            {
                method();
            }
        }

        public void LoadTree()
        {
            try
            {
                this.m_tvTFSMap.BeginUpdate();
                this.m_tvTFSMap.Nodes.Clear();
                IEnumerable<TreeNode> enumerable = null;
                lock (this.m_itemsTreeMAP)
                {
                    this.m_itemsTreeMAP.Clear();
                    List<WIObject> items = new List<WIObject>();
                    WIObjectsStore.NewServers += OnNewChildItems;
                    WIObjectsStore.PreRemoveServers += OnPreRemoveChildItems;
                    foreach (WIObject obj2 in WIObjectsStore.Servers)
                    {
                        items.Add(obj2);
                    }
                    enumerable = this.InitNodes<WIObject>(items);
                }
                foreach (TreeNode node in enumerable)
                {
                    this.m_tvTFSMap.Nodes.Add(node);
                }
                this.m_tvTFSMap.Sort();
                this.ExpandSelectedNode();
            }
            finally
            {
                this.m_tvTFSMap.EndUpdate();
            }
        }

        private void OnAfterNodeSelect(object sender, TreeViewEventArgs args)
        {
            TreeNodeTag<WIObjectType> tag = args.Node.Tag as TreeNodeTag<WIObjectType>;
            this.SelectedObject = tag.Tag as WIObject;
            switch (this.SelectedObject.Type)
            {
                case WIObjectType.Server:
                    this.TreeView.SelectedNode.SelectedImageIndex = 0;
                    break;

                case WIObjectType.Project:
                    this.TreeView.SelectedNode.SelectedImageIndex = 1;
                    break;

                case WIObjectType.QueriesRoot:
                    this.TreeView.SelectedNode.SelectedImageIndex = 2;
                    break;

                case WIObjectType.QueriesGroup:
                    if ((this.SelectedObject as WIQueriesGroup).QueryScope != QueryScope.Public)
                    {
                        this.TreeView.SelectedNode.SelectedImageIndex = 4;
                        break;
                    }
                    this.TreeView.SelectedNode.SelectedImageIndex = 3;
                    break;

                case WIObjectType.Query:
                    this.TreeView.SelectedNode.SelectedImageIndex = 5;
                    break;
            }
        }

        private void OnNewChildItems<T>(object sender, IEnumerable<T> items) where T : WIObject
    {
        MethodInvoker method = delegate { InitItems<T>(items); };
        if (base.InvokeRequired)
        {
            base.Invoke(method);
        }
        else
        {
            method();
        }
    }

        private void OnPreRemoveChildItems<T>(object sender, IEnumerable<T> items) where T : WIObject
    {
        MethodInvoker method = delegate { RemoveItems<T>(items); };

        if (base.InvokeRequired)
        {
            base.Invoke(method);
        }
        else
        {
            method();
        }
    }

        private void OnTfsTreeKeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.F2 && m_selObject.Type == WIObjectType.Query)
            {
                QueryRename(this, EventArgs.Empty);
            }

            if (e.KeyCode == Keys.Delete && m_selObject.Type == WIObjectType.Query)
            {
                QueryDelete(this, EventArgs.Empty);
            }
        }

        public void RaiseSelectionChanged()
        {
            if (this.SelectionChanged != null)
            {
                this.SelectionChanged(this, EventArgs.Empty);
            }
        }

        private void RemoveItems<T>(IEnumerable<T> items) where T : WIObject
        {
            try
            {
                this.m_tvTFSMap.BeginUpdate();
                lock (this.m_itemsTreeMAP)
                {
                    foreach (T local in items)
                    {
                        TreeNode node = this.m_itemsTreeMAP[local.ID];
                        this.RemoveNodes<WIObject>(local.ChildItems);
                        node.Remove();
                    }
                }
            }
            finally
            {
                this.m_tvTFSMap.EndUpdate();
            }
        }

        private void RemoveNodes<T>(IEnumerable<T> items) where T : WIObject
        {
            lock (this.m_itemsTreeMAP)
            {
                foreach (T local in items)
                {
                    TreeNode node = this.m_itemsTreeMAP[local.ID];
                    this.RemoveNodes<WIObject>(local.ChildItems);
                    node.Remove();
                }
            }
        }

        // Properties
        public Guid GuidNodeExpand
        {
            get
            {
                return this.m_guidNodeExpand;
            }
            set
            {
                this.m_guidNodeExpand = value;
            }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false)]
        public WIObject SelectedObject
        {
            get
            {
                return this.m_selObject;
            }
            set
            {
                if (this.m_selObject != value)
                {
                    this.m_selObject = value;
                    this.RaiseSelectionChanged();
                }
            }
        }

        public TreeView TreeView
        {
            get
            {
                return this.m_tvTFSMap;
            }
        }
        
    }
}
